package com.runa.rccprotocol.analysis;

import com.runa.monitor.comm.dto.newComm.PanelVO;
import com.runa.persistence.util.LogUtil;
import com.runa.protocol.analysis.ShellBufferAnalysis;
import com.runa.protocol.dto.DtuReport;
import com.runa.protocol.enums.ByteOrder;
import com.runa.protocol.util.ByteUtil;
import com.runa.rccprotocol.dto.ConcentratorElectric;
import com.runa.rccprotocol.dto.equdata.ConcenReportData;
import com.runa.rccprotocol.dto.jntmp.JingNengAck;
import com.runa.rccprotocol.dto.runa.RunaConcenResponseData;
import org.aspectj.util.FileUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.*;

public class JingNengAnalysis extends ShellBufferAnalysis<byte[]> {

    private static final Logger logger = LoggerFactory.getLogger(JingNengAnalysis.class);

    public JingNengAnalysis() {
        super(null, 128);
    }

    public static void main(String[] args) {
        JingNengAnalysis jingNengAnalysis = new JingNengAnalysis();
        String s = "5763536A2C00023836313536313036313139303539300000003C001FFF00000000000290206667E300FFFF371D6667E400FFFF5E";
        byte[] data = ByteUtil.hexStringToByte(s);
        jingNengAnalysis.fill(data, data.length, null);
    }

    @Override
    public int fill(byte[] data, int length, String netEquNo) {
        if (length < 8) return -1;
        if (ByteUtil.byteToUInt(data, 0, ByteOrder.ABCD) == 0x5763536A) {
            int dataLen = ByteUtil.byteToShort(data, 4, ByteOrder.BA);
            if (length >= 8 + dataLen && ByteUtil.xorSum(data, 0, 7 + dataLen) == data[7 + dataLen]) {
                int cmd = data[6];
                if (cmd == 1) {
                    String deviceKey = new String(data, 7, 15);
                    int version = data[25] * 100 + data[26];
                    boolean update = firmwareUpdate(version);
                    String iccid = new String(data, 27, 20);
                    this.netEquNo = deviceKey;
                    LogUtil.linkDetect(this.netEquNo, "京能", data, length, "注册[cmd=1]");
                    ConcenReportData reportData = new ConcenReportData();
                    reportData.setVer(String.valueOf(version));
                    reportData.setIccid(iccid);
                    ConcentratorElectric register = new ConcentratorElectric(deviceKey);
                    register.setMustAck(true);
                    register.setAck(new JingNengAck(0x81, deviceKey, update ? 1 : 0));
                    register.setReportData(reportData);
                    interData = register;
                } else if (cmd == 2) {
                    List<PanelVO> panelVOS = new ArrayList<>();
                    String deviceKey = new String(data, 7, 15);
                    this.netEquNo = deviceKey;
                    LogUtil.getLogAndInfo(this.netEquNo, "京能", "[cmd=2]: {}", ByteUtil.byteToHexString(data, 0, length));
                    int peri = ByteUtil.byteToShort(data, 25, ByteOrder.BA);
                    int csq = data[27];
                    int battery = data[28];
                    int count = data[34];
                    int index = 35;
                    for (;count > 0; count--) {
                        PanelVO panelVO = new PanelVO();
                        panelVO.setSerial(deviceKey);
                        panelVO.setReadTime(new Date());
                        panelVO.setPanelDate(new Date(ByteUtil.byteToUInt(data, index, ByteOrder.DCBA) * 1000));
                        index += 4;
                        panelVO.setTemperature((float) (ByteUtil.byteToShort(data, index, ByteOrder.BA) * 0.1));
                        index += 2;
                        int humidity = ByteUtil.byteToShort(data, index, ByteOrder.BA);
                        index += 2;
                        if (humidity > 0) panelVO.setHumidity((float) (humidity * 0.1));
                        panelVO.setSignal(String.valueOf(csq));
                        if (battery > 0) panelVO.setBatteryVol((float) battery);
                        panelVOS.add(panelVO);
                    }
                    RunaConcenResponseData responseData = new RunaConcenResponseData();
                    responseData.addRepData(panelVOS);
                    responseData.setAck(new JingNengAck(0x82, this.netEquNo, 0));
                    responseData.setUpward(true);
                    responseData.setAddress(this.netEquNo);
                    interData = responseData;
                } else if (cmd == 4) {
                    String deviceKey = new String(data, 7, 15);
                    int version = ByteUtil.byteToUShort(data, 25, ByteOrder.BA);
                    int offset = ByteUtil.byteToUShort(data, 27, ByteOrder.BA);
                    int size = ByteUtil.byteToUShort(data, 29, ByteOrder.BA);
                    this.netEquNo = deviceKey;
                    LogUtil.linkDetect(this.netEquNo, "京能", data, length, "注册[cmd=4]");
                    DtuReport register = new DtuReport(deviceKey);
                    register.setMustAck(true);
                    byte[] firmware = versionFirmware.get(version);
                    byte[] update = new byte[size];
                    System.arraycopy(firmware, offset, update, 0, size);
                    register.setAck(new JingNengAck(0x84, deviceKey, offset, firmware.length, update));
                    interData = register;
                } else {
                    LogUtil.getLogAndInfo("jn", "京能", "[cmd=2]: {}", ByteUtil.byteToHexString(data, 0, length));
                }
                return length - dataLen - 8;
            }
        }
        return 0;
    }

    private final Map<Integer, byte[]> versionFirmware = new HashMap<>();

    private boolean firmwareUpdate(int version) {
        String firmwareDir = "/runa/akr_firmware/";
        try {
            String[] fws = FileUtil.listFiles(new File(firmwareDir));
            logger.info("version: {}, akr_firmware: {}", version, Arrays.asList(fws));
            for (String firmware : fws) {
                if (firmware.contains("v"+version)) {
                    versionFirmware.put(version, FileUtil.readAsByteArray(new File(firmwareDir+firmware)));
                    return true;
                }
            }
        } catch (Exception e) {
            logger.error("firmwareUpdate: {}", e);
        }
        return false;
    }

}
